

import rb, rhythmdb
import pygtk, gtk, gtk.glade
import gobject
import gconf, gnomevfs, gnome
import urllib
import datetime
import pygst
import gst
import time
import random
import re
import os
import gnome.ui

import inspect

import VideoSourceConfigDlg

import TrackerVideoBackend

LOAD_DIRECTORY_FLAGS = gnomevfs.FILE_INFO_GET_MIME_TYPE | gnomevfs.FILE_INFO_FOLLOW_LINKS
ITEMS_PER_NOTIFICATION = 20
"""
#TODO:
* season-episode processing		almost finished
* keep_spect_ratio				DONE
* audio language switching		
* subtitles language			
* improve support for filetypes (some just won't play that work in totem)
"""

class VideoSource(rb.BrowserSource):
	__gproperties__ = {
		'db': (rhythmdb.RhythmDB, 'db', 'db', gobject.PARAM_READABLE |gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
	}
	def __init__(self):
		rb.BrowserSource.__init__(self)
		self.__db = None
		self.__updatingDirs = []
		self.__shell = None
		self.__updating = False
		self.__activated = False
		self.__crawled_on_startup = False
		self.__load_handle = None
		self.__entry_type = None
		self.__entry_view = None
		self.__elapsed_change_cb_id = 0
		self.__library_monitor_handle = None
		self.__hashRe = re.compile('(\[[0-9a-f]{8}\])',re.IGNORECASE)
		self.__yearFindRegEx = re.compile('[\s(]\d{4}[)\s]?.*$')
		self.__yearFindRegEx2 = re.compile('\d{4}')
		self.__seasonEpisodeRe_01x02 = re.compile('([0-9]+)x([0-9]+)',re.IGNORECASE) # matches 01x02
		self.__seasonEpisodeRe_s01e02 = re.compile('[sS(Season)]([0-9]+)[eE(Episode)]([0-9]+)',re.IGNORECASE) # matches s01e02
		self.__seasonEpisodeRe__13_ = re.compile('(\s)([0-9]{1,3})(\s|v|\[|$)',re.IGNORECASE) # matches - 13 -
		self.__removeTheseRe = re.compile('(Episode|XviD[0-9]\.[0-9]|xvid|dvdrip|divx|dvdscr)',re.IGNORECASE)
		self.__removeTheseRe2 = re.compile('\(\s*\)',re.IGNORECASE)
		self.__replaceMultipleSpaces = re.compile('( + +)')
		self.__playbin_ref = None
		self.__subtitle_font = 'Sans 25'
		self.tvs = TrackerVideoBackend.TrackerVideoBackend()
		#TODO: season/episode regex:
		#S02E19: [\\/]
		#01x01:  ([0-9]+)x([0-9]+)[^\\/]*
		#_15_
		# - 15\W
		
#		
		#self.__library_path = None
		#library_path = gconf.client_get_default().get_string(VideoSourceConfigDlg.gconf_keys['library'])

		#self.setLibrary(library_path)
	def row_inserted_cb(self,a1):
		print a1
	def element_added_cb(self,bin,element):
		if(not element):
			return
		element_name = element.get_name()
		print element_name
		if(element_name not in ('textbin', 'vbin')):
			return

		if(element_name == 'textbin'):
			try:
				overlay = element.get_by_name('overlay')
				overlay.set_property('font-desc',self.__subtitle_font)
				#does not look nice
				#overlay.set_property('shaded-background',True)
			except Exception,e:
				print "Could not set subtile font description"
				print e

	def set_subtitle_font(self):
		pass
	def do_impl_get_status(self):
		qm = self.get_property("query-model")
		if self.__updating:
			text = _("Updating Video Library: %s") % qm.compute_status_normal("%d song", "%d songs")
			return (text, None, random.random())
		else:
			return (qm.compute_status_normal("%d song", "%d songs"), None, 0.0)
	def do_set_property(self, property, value):
		if property.name == 'plugin':
			self.__plugin = value
		else:
			if property.name == 'db':
				self.__db = value#
			else:
				raise AttributeError, 'unknown property %s' % property.name
	def do_get_property(self,property):
		if property.name == 'db':
			return self.__db
	def do_impl_activate(self):
		if not self.__activated:
			self.__shell = self.get_property('shell')
			self.__entry_type = self.get_property('entry-type')
			
			if not self.__crawled_on_startup:
				if self.__db == None:
					self.__db = shell.get_property('db')
				self.__activated = True
				self.initialize_playbin()
				#self.__showCustomView(True)
				#self.__entry_view = rb.EntryView(self.__db,self.__shell.get_player(),'/video/',False,False)

				
				#self.__entry_view
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_TITLE, TRUE);
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_GENRE, FALSE);
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_QUALITY, FALSE)
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_RATING, FALSE);
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);*/
				#rb_entry_view_append_column (source->priv->stations, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
				# start our catalogue updates
				#self.__update_id = gobject.timeout_add(6 * 60 * 60 * 1000, self.__update_catalogue)
				self.__crawled_on_startup = True
				self.__update_catalogue()
		rb.BrowserSource.do_impl_activate (self)
#	def do_impl_get_entry_view(self):
#		print self.__entry_view
#		return self.__entry_view
	def __update_catalogue(self):
		self.__updating = True
		self.__load_catalogue()
		#rb.BrowserSource.do_impl_activate (self)
	def __showCustomView(self,show):
		self.get_entry_view().set_no_show_all (not show)
	def __load_catalogue(self):
		vids = self.tvs.get_all_videos()
		for res in vids:
			print (res[1],int(res[2]))
			gobject.idle_add(self.__addVideofile,res[0], res[1], int(res[2]))
		pass
	def addDir(self,uri):
			#print "Entering %s" %uri
			self.__updatingDirs.append(uri)
			self.__updating = True
			return gnomevfs.async.load_directory(uri, self.__load_catalogue_open_cb,LOAD_DIRECTORY_FLAGS, ITEMS_PER_NOTIFICATION,data=(uri))
	def __load_catalogue_open_cb(self,handle,file_infos,exc_type,base_url):
		"""Load the catalog on Startup"""
		"""Things todo: 
			1. iterate over the entire library and add files not already in the db
			2. remove files from the library
		"""
		self.__updating = True
		if not exc_type or exc_type == gnomevfs.EOFError:
			#print handle
			for f in file_infos:
				if(f.name in (".", "..")):
					continue
				if(f.type == 2):
					new_uri = (base_url.append_path(f.name))
					if((new_uri != base_url) and (base_url.is_parent(new_uri))):
						#print "dir: %s" % new_uri
						self.addDir(new_uri)
						pass
				else:
					try:
						if f.mime_type.startswith ("video/") or f.mime_type == 'application/x-flash-video' and f.permissions & gnomevfs.PERM_USER_READ :
							#results.append (f.name)
							gobject.idle_add(self.__addVideofile,base_url.append_file_name(f.name),f)
							pass
					except:
						pass


					

		if exc_type == gnomevfs.EOFError:
			self.__updatingDirs.remove(base_url)
			self.__updating = False
			if len(self.__updatingDirs) == 0:
				print "The whole library was updated."
		self.__update_ui()
	#obsolete
	def update_metadata_cb(self):
		gtk.gdk.threads_enter()
		finished = self.update_metadata()
		if not finished:
				gtk.gdk.threads_leave()
				return True
		gtk.gdk.threads_leave()
		return False
	def __addVideofile(self,uri,short_name,duration = 0):
		track_uri = "%s" % uri
		entry = self.__db.entry_lookup_by_location (track_uri)
		if entry == None:
			entry = self.__db.entry_new(self.__entry_type, track_uri)
		title = urllib.unquote(short_name)
		# translate the separators to whitspace
		title = re.sub(self.__removeTheseRe,'',title)
		title = re.sub(self.__removeTheseRe2,'',title)
		for item in ['_','.',' - ']:
			title = title.replace(item,' ')
		
		#remove the 8-character hashes
		ani_hash_list = self.__hashRe.findall(title)
		for item in ani_hash_list:
			title = title.replace(item,'')
		#move the (anime) group to the end
		if(title[0] == '['):
			end_pos = (int)(title.find(']',3))
			group = title[0:end_pos+1]
			title = title.replace(group,'')
			title = "%s %s" %(title,group)
			title = title.strip()
			pass
		# if year is not set, use launch date instead
		try:
			year_list = self.__yearFindRegEx.findall(title)
			year_list = self.__yearFindRegEx2.findall(year_list[-1])
			year = year_list[-1]
		except:
			year = -1
		s01e01 = ""
		if(s01e01 == ""):
			season_episode = []
			season_episode = self.__seasonEpisodeRe_01x02.findall(title)	
			print 
			if(len(season_episode) > 0):
				season_episode = season_episode[0]
				season = (int)(season_episode[0])
				episode = (int)(season_episode[1])
				if (season < 100):
					s01e01 = "%02dx%02d" %(season,episode)
		if(s01e01 == ""):
			season_episode = self.__seasonEpisodeRe_s01e02.findall(title)	
			#print season_episode
			if(len(season_episode) != 0):
				#print season_episode
				season_episode = season_episode[0]
				season = (int)(season_episode[0])
				episode = (int)(season_episode[1])
				if (season < 100):
					s01e01 = "S%02dE%02d" %(season,episode)
		if(s01e01 == ""):
			season_episode = self.__seasonEpisodeRe__13_.findall(title)	
			#print season_episode
			if(len(season_episode) != 0):
				episode = (int)(season_episode[0][1])
				s01e01 = "E%02d" %(episode)				
		
		if(s01e01 != ""):
			#print title
			#self.__db.set(entry, rhythmdb.PROP_TRACK_NUMBER, title)
			self.__db.set(entry, rhythmdb.PROP_ARTIST, s01e01)

		title = re.sub(self.__replaceMultipleSpaces,' ',title)
		self.__db.set(entry, rhythmdb.PROP_TITLE,title)
		album = "Unknown"
		self.__db.set(entry, rhythmdb.PROP_ALBUM,album)
		if(year > -1):
			date = datetime.date((int)(year), 1, 1).toordinal()
			self.__db.set(entry, rhythmdb.PROP_DATE, date)
		self.__db.set(entry, rhythmdb.PROP_DURATION, duration)
		#TODO: Add the genre
		self.__db.commit()
		#gobject.idle_add(self.__get_metadata,entry)
		#self.__get_metadata(entry)
		return False
	def __library_change_detected(self,a1,a2):
		print "a1: %s" %a1
		print "a2: %s" %a2
		pass
	def __get_metadata(self,entry):
		if entry == None:
			print "Track not found in DB"
			return True
		duration = gst.CLOCK_TIME_NONE
		try: 
			#duration,format = self.__playbin_ref.query_duration (gst.FORMAT_TIME)
			duration,format = self.__shell.get_player().get_property('player').get_property('playbin').query_duration (gst.FORMAT_TIME)
			if(duration != gst.CLOCK_TIME_NONE):
				self.__db.set(entry, rhythmdb.PROP_DURATION, duration/1000000000)
				self.__db.commit()
			print "duration: %s" %(duration)
		except Exception,e:
			print "could not query duration"
			print e
			pass
	def __elapsed_change_cb(self,position,a):
		entry = self.__shell.get_player().get_playing_entry()
		if (self.__db.entry_get(entry, rhythmdb.PROP_DURATION) == 0):
			self.__get_metadata(entry)
		else:
			if(self.__elapsed_change_cb_id):
				self.__shell.get_player().disconnect(self.__elapsed_change_cb_id)
		return False
	def build_cover_art(self,uri):
		try:
			file_info = gnomevfs.get_file_info(uri,LOAD_DIRECTORY_FLAGS)
			factory = gnome.ui.ThumbnailFactory(gnome.ui.THUMBNAIL_SIZE_NORMAL)
			pixbuf = factory.generate_thumbnail(uri,file_info.mime_type)
			factory.save_thumbnail(pixbuf,uri,file_info.mtime)
		except Exception,e:
			print e
		return False
	def set_cover_art(self,entry):
		uri = entry.get_playback_uri()
		thumb_path =  gnome.ui.thumbnail_path_for_uri(uri,gnome.ui.THUMBNAIL_SIZE_NORMAL)
		pixbuf = None
		try:
			pixbuf = gtk.gdk.pixbuf_new_from_file(thumb_path)
			print "Changing thumbnail"
			self.__db.emit_entry_extra_metadata_notify (entry, 'rb:coverArt-uri',thumb_path)
		except Exception,e:
			#gobject.idle_add(self.build_cover_art,uri)
			pass
		return False
	def playing_changed(self,playing):
		if(playing == False):
			return
		if not self.__db or  not self.__shell:
			return
		entry = self.__shell.get_player().get_playing_entry()
		if not entry or entry.get_entry_type() != self.__entry_type:
			return

#		for i in self.__shell.get_player ().get_property ('player').get_property('playbin').elements():
#			print "%s: %s" %(i.get_name(),i)
		#query for the visualization action everytime
		toggle_action = None
		try:
			toggle_action = self.__shell.get_player().get_property('ui-manager').get_action("/ToolBar/PluginPlaceholder/Visualization")
		except:
			pass
		#print toggle_action
		if(toggle_action):
			#toggle the visualization
			toggle_action.set_active(True)
			#assign the playbin reference and connect the element added signal
			self.initialize_playbin()
#			
#			if(self.initialize_playbin()):
#				#fake the element added events 
#				try:
#					textbin = self.__playbin_ref.get_by_name('textbin')
#					self.__playbin_ref.emit("element-added",textbin)
#				except Exception,e:
#					print e
#					pass
#				#fake the element added events 
#				try:
#					videosink = self.__playbin_ref.get_by_name('vbin')
#					self.__playbin_ref.emit("element-added",videosink)
#				except Exception,e:
#					print e
#					pass

		self.__update_ui()
		gobject.idle_add(self.set_cover_art,entry)

	def pause_player(self,player):
		self.set_player_state(player, gst.STATE_PAUSED)
	def stop_player(self,player):
		self.set_player_state(player, gst.STATE_NULL)
		#player.set_property('uri',None)
	def set_player_state(self,player,state):
		state_ret = player.set_state(state),
		#wait for the state change, this means that all the metadata was read.
		#do this for a maximum of 5 times, it migth be that the 
		change_timeout = 0
		#print "Preparing state change: %s" % state
		bus = player.get_bus()
		#print state_ret
		while (gst.STATE_CHANGE_SUCCESS not in state_ret):
			msg = bus.poll(gst.MESSAGE_DURATION, 1*gst.SECOND)
			state_ret = player.get_state(1)
		#print " New state:"
		#print state_ret
	def initialize_playbin(self):
		if(not self.__playbin_ref):
			try:
				self.__playbin_ref = self.__shell.get_player().get_property ('player').get_property('playbin')
				if(self.__playbin_ref):
					self.__playbin_ref.connect("element-added",self.element_added_cb)
					bus = self.__playbin_ref.get_bus()
					print "BUS: %s" % bus
					bus.add_signal_watch()
					bus.enable_sync_message_emission()
					bus.connect('sync-message::element', self.on_sync_message)
					return True
			except Exception,e:
				print e
		else:
			return True
		return False
	def playing_entry_changed(self,entry):
		if(not entry):
			return
		if entry.get_entry_type() != self.__entry_type:
			return
		if not self.__db or not self.__shell:
			return
		if(self.__elapsed_change_cb_id):
			try:
				self.__shell.get_player().disconnect(self.__elapsed_change_cb_id)
			except:
				pass
		if (self.__db.entry_get(entry, rhythmdb.PROP_DURATION) == 0):
			self.__elapsed_change_cb_id = self.__shell.get_player().connect("elapsed-changed",self.__elapsed_change_cb)
			#self.__get_metadata(entry.get_playback_uri())

	def __update_ui(self):
		self.__shell.get_player().get_property('ui-manager').ensure_update()
	def setLibrary(self,path):
		if(path[-1] == '/'):
			path = path[:-1]
		if(path[0] == "/"):
			path = "file://%s"%path
		#self.__library_path = path
	def getLibraryUri(self):
		return "/tmp/" #self.__library_path
	
	def on_sync_message(self, bus, message):
		#print "on_sync_message on_sync_message on_sync_message on_sync_message on_sync_message on_sync_message on_sync_message on_sync_message on_sync_message"
		if message.structure is None:
			return
		message_name = message.structure.get_name()
		if message_name == 'prepare-xwindow-id':
			imagesink = message.src
			imagesink.set_property('force-aspect-ratio', True)
			
gobject.type_register(VideoSource)

